#ifndef JTHREADPOOL_H
#define JTHREADPOOL_H

#include <JXQCore/JRunnable>
#include <functional>
#include <future>

namespace JXQ
{

class JThreadPoolPirvate;

// 线程池
class JXQLIB_EXPORT JThreadPool
{
public: // 最大线程数量  最大队列长度
	explicit JThreadPool(uint32_t maxCount = 1, int maxQueue = -1,
						 int expiryTimeout = 300000); // 5min
	~JThreadPool();

public:
	template <typename Func, typename...Args>
	auto start(Func &&func, Args&&... args)
	-> std::future<decltype(func(args...))>;

	template <typename Func, class Class, typename...Args>
	auto start(Func &&func, Class *obj, Args&&... args)
	-> std::future<decltype((obj->*func)(args...))>;

	std::future<void> start(JRunnable *runnable);

public:
	template <typename Ret> std::future<Ret>
	operator<<(std::function<Ret()> &func);

	template <typename Ret> std::future<Ret>
	operator<<(std::function<Ret()> &&func);

	std::future<void> operator<<(JRunnable *runnable);

public:
	int threadAvailableCount() const;
	int activeThreadCount() const;
	int threadCount() const;

public:
	void setMaxThreadCount(uint32_t max);
	int maxThreadCount() const;

	void setMaxQueueLength(int max);
	int maxQueueLength() const;

	void setExpiryTimeout(uint32_t msecs); //容易惊群
	uint32_t expiryTimeout() const;

public:
	static JThreadPool &globalInstance();
	bool wait(int msecs = -1); //等待线程结束

private:
	J_DISABLE_COPY(JThreadPool)
	void yield(std::function<void()> &&task);
	JThreadPoolPirvate *d_ptr;
};

template <typename Func, typename...Args>
auto JThreadPool::start(Func &&func, Args&&... args)
-> std::future<decltype(func(args...))>
{
	using namespace std;
	using Pt = packaged_task<decltype(func(args...))()>;
	auto package = make_shared<Pt>(bind(forward<Func>(func), forward<Args>(args)...));
	yield([package](){(*package)();});
	return package->get_future();
}

template <typename Func, class Class, typename...Args>
auto JThreadPool::start(Func &&func, Class *obj, Args&&... args)
-> std::future<decltype((obj->*func)(args...))>
{
	using namespace std;
	using Pt = packaged_task<decltype((obj->*func)(args...))()>;
	auto package = make_shared<Pt>
				   (bind(std::forward<Func>(func), obj, forward<Args>(args)...));
	yield([package](){(*package)();});
	return package->get_future();
}

template <typename Ret> std::future<Ret> JThreadPool::
operator<<(std::function<Ret()> &func) { return start(func); }

template <typename Ret> std::future<Ret>
JThreadPool::operator<<(std::function<Ret()> &&func)
{ return start(std::forward<std::function<Ret()>>(func)); }

inline std::future<void> JThreadPool::operator<<(JRunnable *runnable)
{ return start(runnable); }

} //namespace JXQ


#endif //JTHREADPOOL_H

